Skip to main content

App Open

App Open ads are full-screen ads that appear when users launch your app, providing an excellent opportunity to monetize app startup moments. Unlike interstitial ads, App Open ads are specifically designed for app launch scenarios and help create a smooth user experience during cold starts and app foregrounding events.

Key Features

  • Launch Optimization: Designed specifically for app startup scenarios
  • User-Friendly: Integrates seamlessly with splash screens and loading experiences
  • Revenue Maximization: Monetizes high-engagement moments when users actively open your app
  • Retention-Focused: Built with user retention best practices in mind

Best Practices

Implementation Guidelines
  • Always use a splash/loading screen before showing the App Open ad
  • Inform users about the upcoming ad with a message like "Watch an ad from our sponsor while the app loads"
  • Ensure proper sequence: Splash screen → App Open ad → App content
  • Initialize the SDK before loading App Open ads
Frequency Management

To maintain good user experience and retention:

  • Implement external frequency capping outside of the SDK
  • Consider cooldown periods between App Open ads
  • Wait for new users to engage with your app before showing their first App Open ad
  • Show ads strategically (e.g., every 2nd or 3rd app launch)

Start loading an ad

Load App Open ads during SDK initialization, ideally in your AppDelegate or SceneDelegate.

import XMediator

XMediatorAds.startWith(appKey: "<your-app-key>") { result in
XMediatorAds.appOpen.load(placementId: "<placement-id>")
}

Presenting an ad

Calling isReady() will return if there's an App Open ad available to be presented, regardless of its placement id. If multiple ads with different placement ids were previously loaded, the SDK will try to present the best one available.

if XMediatorAds.appOpen.isReady() {
XMediatorAds.appOpen.present(fromViewController: self, fromAdSpace: "app-open-ad-space")
}

Presenting an ad with placementId

When the app needs to present an ad for a specific placement id, isReady(withPlacementId:) and present(withPlacementId:) can be alternatively used.

if XMediatorAds.appOpen.isReady(withPlacementId: "<placement-id>") {
XMediatorAds.appOpen.present(withPlacementId: "<placement-id>", fromViewController: self, fromAdSpace: "app-open-ad-space")
}

Built-in features

Auto loading

When App Open ads are dismissed or fail to show, the SDK automatically triggers a new load request to ensure the next app launch opportunity is ready.

Auto retry

Failed load attempts are automatically retried with exponential backoff, ensuring optimal fill rates for your app launch monetization.

Additional settings

Register ad callbacks

Every ad callback indicates the placement id of the App Open ad that triggered the event.

// Assign a delegate to handle the ad callbacks
XMediatorAds.appOpen.addDelegate(self)

// [...]

func didLoad(placementId: String, result: LoadResult) {
print("App Open loaded! placementId: \(placementId)")
}

func didPresent(placementId: String) {
print("App Open is being presented! placementId: \(placementId)")
}

func failedToPresent(placementId: String, error: PresentError) {
// If you need to resume your app's flow, make sure to do it here and in the didDismiss callback
print("App Open failed to present. placementId: \(placementId), Reason: \(error.localizedDescription)")
}

func didRecordImpression(placementId: String, data: ImpressionData) {
print("App Open impression, with revenue: \(data.revenue). placementId: \(placementId)")
}

func willDismiss(placementId: String) {
print("App Open will be dismissed! placementId: \(placementId)")
}

func didDismiss(placementId: String) {
// If you need to resume your app's flow, make sure to do it here and in the failedToPresent callback
print("App Open dismissed! placementId: \(placementId)")
}

func didClick(placementId: String) {
print("App Open clicked! placementId: \(placementId)")
}

App Lifecycle Integration

For optimal App Open ad implementation, integrate with iOS's lifecycle events:

import UIKit

class AppDelegate: UIResponder, UIApplicationDelegate {

private var appOpenListener: AppOpenListener?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Initialize the SDK
XMediatorAds.startWith(appKey: "your_app_key") { result in
// Load an App Open ad for future use
XMediatorAds.appOpen.load("app_open_placement_id")
}

// Set up listener
appOpenListener = AppOpenListener()
XMediatorAds.appOpen.addListener(appOpenListener!)

// Add notification observers for app lifecycle events
NotificationCenter.default.addObserver(
self,
selector: #selector(applicationWillEnterForeground),
name: UIApplication.willEnterForegroundNotification,
object: nil
)

return true
}

@objc func applicationWillEnterForeground() {
// App comes to foreground - show App Open ad if ready
if XMediatorAds.appOpen.isReady() {
// Get current view controller and show ad
if let rootViewController = UIApplication.shared.windows.first?.rootViewController {
XMediatorAds.appOpen.present(viewController: rootViewController, adSpace: "app-open-ad-space")
}
}
}
}

Code example

In addition to the example below, you can see a real implementation in our iOS Demo App.

AppOpenViewController.swift
import UIKit
import XMediator

class AppOpenViewController: UIViewController {
@IBOutlet weak var splashProgressBar: UIActivityIndicatorView!
@IBOutlet weak var splashMessage: UILabel!

private let appKey = "<your-app-key>"
private let appOpenPlacementId = "<placement-id>"

override func viewDidLoad() {
super.viewDidLoad()
setupSplashUI()
initializeSDKAndLoadAd()
}

private func setupSplashUI() {
// Show user-friendly message about upcoming ad
splashMessage.text = "Watch an ad from our sponsor while the app loads..."
splashProgressBar.startAnimating()
}

private func initializeSDKAndLoadAd() {
XMediatorAds.appOpen.addDelegate(self)

// Initialize SDK and load App Open ad
XMediatorAds.startWith(appKey: appKey) { result in
XMediatorAds.appOpen.load(placementId: self.appOpenPlacementId)
}

// Show ad after a short delay to ensure splash screen is visible
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.showAppOpenAdIfReady()
}
}

private func showAppOpenAdIfReady() {
if XMediatorAds.appOpen.isReady(withPlacementId: appOpenPlacementId) {
XMediatorAds.appOpen.present(withPlacementId: appOpenPlacementId, fromViewController: self, fromAdSpace: "app-open-ad-space")
} else {
// No ad ready, proceed to main app
proceedToMainApp()
}
}

private func proceedToMainApp() {
// Hide splash elements and show main app content
splashProgressBar.stopAnimating()
splashProgressBar.isHidden = true
splashMessage.text = "Welcome to the app!"

// Navigate to main view controller or show main content
// performSegue(withIdentifier: "showMainApp", sender: self)
}
}

extension AppOpenViewController: AppOpenAdsDelegate {
func didLoad(placementId: String, result: LoadResult) {
print("App Open loaded! placementId: \(placementId)")
}

func didPresent(placementId: String) {
print("App Open is being presented! placementId: \(placementId)")
// Hide splash screen when ad is shown
splashProgressBar.stopAnimating()
splashProgressBar.isHidden = true
}

func failedToPresent(placementId: String, error: PresentError) {
// If you need to resume your app's flow, make sure to do it here and in the didDismiss callback
print("App Open failed to present. placementId: \(placementId), Reason: \(error.localizedDescription)")
proceedToMainApp()
}

func didRecordImpression(placementId: String, data: ImpressionData) {
print("App Open impression, with revenue: \(data.revenue). placementId: \(placementId)")
}

func willDismiss(placementId: String) {
print("App Open will be dismissed! placementId: \(placementId)")
}

func didDismiss(placementId: String) {
// If you need to resume your app's flow, make sure to do it here and in the failedToPresent callback
print("App Open dismissed! placementId: \(placementId)")
proceedToMainApp()
}

func didClick(placementId: String) {
print("App Open clicked! placementId: \(placementId)")
}
}

Advanced Use Cases

Need more control over the ad loading and presentation lifecycle? Check out the Advanced App Open API for fine-grained control using individual AppOpen instances.